
package org.hackystat.devcathlon.engine.event.impl;

import static org.junit.Assert.assertEquals;
import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.engine.event.Event;
import org.hackystat.devcathlon.engine.event.EventScore;
import org.hackystat.devcathlon.engine.match.Match;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.test.DevcathlonTestHelper;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.Test;
import org.junit.BeforeClass;


/**
 * Test Pass The Build Starter Event.
 * 
 * @author Ka Hung Phillip Lau
 */
public class TestPassTheBuild extends DevcathlonTestHelper {

  /** The actual bonus weight. */
  private static int bonusWeight = 10;
  /** The actual bonus range. */
  private static int bonusRange = 7;
  /** The actual success build weight. */
  private static int successWeight = 1;
  /** The actual failed build weight. */
  private static int failedWeight = -1;
  
  private String teamName = "TestTeam";
  private String teamOwner = "TeamOwner";
  private String matchName = "TestMatch";
  private String member1 = "Member1";
  private String member2 = "Member2";

  /**
   * Sets up the DevcathlonConfiguration for use in these test cases. 
   * @throws Exception If problems occur setting up the configuration. 
   */
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    // Set up the testing DevcathlonConfiguration for PassTheBuild.
    String eventName = PassTheBuild.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 1);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 1440);
    configManager.addProperty(eventName, PassTheBuild.successWeightKey, 
        String.valueOf(successWeight));
    configManager.addProperty(eventName, PassTheBuild.failedWeightKey, 
        String.valueOf(failedWeight));
    configManager.addProperty(eventName, PassTheBuild.bonusWeightKey, String.valueOf(bonusWeight));
    configManager.addProperty(eventName, PassTheBuild.bonusRangeKey, String.valueOf(bonusRange));
  }
  
  /**
   * Tests this event when there is no sensor data for this team.
   * @throws Exception Unexpected exception.
   */
  @Test
  public void testNoData() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Match match = addSimpleMatch(matchName, team, getProject(teamOwner, teamName), event);
    
    // Test the event with no sensor data.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 1", 0, score.getBaseScore());
    assertEquals("Check points 1", 0, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there is a single build and the build is success. 
   * @throws Exception If there is a bug.
   */
  @Test
  public void testSingleBuildSuccess() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Send a single build data.
    boolean success = true;
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 2", 1, score.getBaseScore());
    assertEquals("Check points 2", 1, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there is a single build and build is failed.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testSingleBuildFailed() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    boolean success = false;
    // Send a build followed by failed build
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 3", -1, score.getBaseScore());
    assertEquals("Check points 3", -1, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there are two builds and builds are Success.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testTwoBuildSuccess() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    // Send a single build data.
    boolean success = true;
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 4", 2, score.getBaseScore());
    assertEquals("Check points 4", 2, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there are two builds and builds are failed.
   * @throws Exception If there is a bug.
   */
  @Test
  public void testTwoBuildFailed() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    boolean success = false;
    // Send a build followed by failed build
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 5", -2, score.getBaseScore());
    assertEquals("Check points 5", -2, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there are two builds.
   * One is success and one is failed.
   * 
   * @throws Exception If there is a bug.
   */
  @Test
  public void testMultipleFailedAndSuccess() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    boolean success = false;
    // Send a build followed by failed build
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), true);
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 6", -1, score.getBaseScore());
    assertEquals("Check points 6", -1, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there are seven builds and all are successful builds.
   * In a seven days period.
   * 
   * @throws Exception If there is a bug.
   */
  @Test
  public void testSuccessBonus() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    XMLGregorianCalendar date = Tstamp.makeTimestamp();
    
    boolean success = true;
    // Send success builds over seven day period.
    for (int i = 1; i <= 7; i ++) {
      makeBuildData(team.getOwner(), project, date, success);
      date = Tstamp.incrementDays(date, -1);

    }
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 7", 11, score.getBaseScore());
    assertEquals("Check points 7", 11, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there are seven builds.
   * One failed and six success.
   * In a seven days period.
   * 
   * @throws Exception If there is a bug.
   */
  @Test
  public void testFailedBonus() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    XMLGregorianCalendar date = Tstamp.makeTimestamp();
    
    boolean success = true;
    boolean success2 = false;
    // Send success builds over seven day period.
    for (int i = 1; i <= 7; i ++) {
      makeBuildData(team.getOwner(), project, date, success);
      date = Tstamp.incrementDays(date, -1);

    }
    // Send a failed build on the seventh day.
    makeBuildData(team.getOwner(), project, date, success2);
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 8", 1, score.getBaseScore());
    assertEquals("Check points 8", 1, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
  
  /**
   * Tests this event when there are eight builds.
   * Two in the same day, six in other days.
   * In a nine day period.
   * 
   * @throws Exception If there is a bug.
   */
  @Test
  public void testSuccessBonus2() throws Exception {
    // Create the team. 
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    // Now create the event instance.
    Event event = new PassTheBuild();
    
    // Create a simple match containing a single team, a single project, and this event.
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    XMLGregorianCalendar date = Tstamp.makeTimestamp();
    
    boolean success = true;
    // Send two successful builds on a same day.
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    makeBuildData(team.getOwner(), project, Tstamp.makeTimestamp(), success);
    date = Tstamp.incrementDays(date, -1);

    // Send success builds over seven day period.
    for (int i = 1; i <= 7; i ++) {

      makeBuildData(team.getOwner(), project, date, success);
      date = Tstamp.incrementDays(date, -1);


    }
    
    // Now compute the event.
    EventScore score = event.computeScore(match, team, Tstamp.makeTimestamp());
    assertEquals("Check base 9", 12, score.getBaseScore());
    assertEquals("Check points 9", 12, event.computePoints(score));
    
    // Cleanup.
    deleteTeam(teamName);
    deleteMatch(matchName);
  }
}
